#ifndef _FCHARMAP_H_
#define _FCHARMAP_H_

namespace Font
{

	class Library;
	class Metrics;

	struct UnicodeRange
	{
		unsigned int start, end;
		UnicodeRange* prev;
		UnicodeRange* next;
	};

	class CharMap
	{

		friend class Metrics;
		friend class MetricsGDI;
	
	public:
	
		// TODO: Follow unicode standard for commands
		// http://en.wikipedia.org/wiki/Unicode#Code_point_planes_and_blocks

		// the following special commands are allowed:
		// :lower:       - lowercase letters
		// :upper:       - uppercase letters
		// :latin:       - all latin characters
		// :digits:      - numbers
		// :punctuation: - non-letter and non-number characters
		// :default:     - same as :lower::upper::digits::punctuation:

		CharMap(Library* a_Library);
		CharMap(Library* a_Library, const tb::StringBase<wchar_t>& a_Range, wchar_t a_Default = L' ');
		CharMap(Library* a_Library, unsigned int a_RangeStart, unsigned int a_RangeEnd, wchar_t a_Default = L' ');
		~CharMap();

		void SetDefaultGlyph(wchar_t a_Glyph);
		void SetLoadUnhandledGlyphs(bool a_State);

		bool AddRange(unsigned int a_Identifier);
		const std::vector<UnicodeRange*>& GetUnicodeRanges();
		bool AddRangeCharacters(const tb::StringBase<wchar_t>& a_String);
		void AddKnownRange(unsigned int a_RangeStart, unsigned int a_RangeEnd);
		void AddRange(UnicodeRange* a_Range);

		int GetCodeSize();
		int GetCodeHighest();
		const tb::StringBase<wchar_t>& GetCodes();
		void SetDefault(wchar_t a_Character);
		wchar_t GetDefault();

		unsigned int GetRangeStart();
		unsigned int GetRangeEnd();

		bool GetInside(wchar_t a_Character);
		bool GetRangeInside(std::vector<UnicodeRange*>& a_Ranges, unsigned int a_RangeStart, unsigned int a_RangeEnd);

		tb::StringBase<wchar_t> Parse(const tb::StringBase<wchar_t>& a_Commands);

		bool Load(const tb::StringBase<wchar_t>& a_Range);
		bool Load(unsigned int a_RangeStart, unsigned int a_RangeEnd);
		void Compile();
	
	protected:

		void _CompileCodes();
		void _AddRange(UnicodeRange* a_Range);

		tb::StringBase<wchar_t> m_Codes;
		bool m_CodesDirty;
		int m_CodeHighest;

		unsigned int m_RangeStart, m_RangeEnd;

		struct Page
		{
			wchar_t* chars;
			unsigned int chars_filled, chars_total;
		};

		Page** m_Pages;
		unsigned int m_PagesTotal;

		struct UnicodeBin
		{
			unsigned int index;
			UnicodeBin* next;
		};

		UnicodeBin* m_BinFirst;
		UnicodeBin* m_BinLatest;
		unsigned int m_BinAdded;

		void _AddBinRange(unsigned int a_Start, unsigned int a_End);

		std::vector<UnicodeRange*> m_Ranges;

		wchar_t m_Default;

		Library* m_Library;
	
	}; // class CharMap

}; // namespace Font
	
#endif